#include "liolib/lioflat.h"

#define DEF_START 1
#define DEF_END 20
#define DEF_SAMPLES 20
#define DEF_POINTS 10
#define DEF_INTER 3
#define GRAPH_POS_Y 80

/*
CSTR formula=_T("(r/r0)^2");
double r0=1;
double func(double r)
{
	return pow2(r/r0);
}


double la=10;
CSTR formula=_T("(r-rs)+(rc-rs)*log((r-rc)/(rs-rc))");
double func(double l)
{
	return l-la*(1+log(l/la));
}
*/

double lt=1,s=2;
CSTR formula=_T("(lt/l)^s");
double func(double l)
{
	return pow(lt/l,s);
}

class Inter:public FlatApplication
{
	int Ni,N,dN,index;
	double rv,iv,arg,error,start,end;
	Vector<double> vy,vx;
	Font fontSmall;
	FlatText tbInter,tbStart,tbEnd,tbSamples,tbPoints;
	FlatButton bPlus,bMin,bInter,bSamples,bCapture,bLog;
	FlatGraph fg;
	Interpolator interpolator;
	SignalStat stat;

	BOOL create();
	void draw2D();
	BOOL listen(WORD id, WORD code, const void *info);

	BOOL setInter(int n);
	void buildData();
	BOOL setSamples(int samples, int points);
	void setInterval(double start, double end);
	void interpolate();
	void reshape();
} inter;
void Inter::interpolate()
{
	interpolator.init(vy,N,start,end,Ni);
	fg.graph.clear();
	stat.clear();
	for(int i=0;i<N*dN;i++)
	{
		arg=start+i*(end-start)/(N*dN-1);
		interpolator.set(arg);
		index=interpolator.getIndex();
		rv=func(arg);
		iv=interpolator.value;
		error=iv-rv;
		stat.add(error);
		fg.graph.addValues();
	}
	fg.graph.update();
}
void Inter::reshape()
{
	FlatApplication::reshape();
	fg.size.set(float(window.width-20),float(window.height-GRAPH_POS_Y-10));
	container.build();
}
BOOL Inter::listen(WORD id, WORD code, const void *info)
{
	if(id==tbInter.id)
	{
		if(code==FLAT_ACTION_DEFAULT)
		{
			setInter(format.toInt(tbInter.text));
		}
	}
	else if(id==bPlus.id)
	{
		if(code==FLAT_ACTION_DEFAULT)
		{
			setInter(Ni+1);
		}
	}
	else if(id==bMin.id)
	{
		if(code==FLAT_ACTION_DEFAULT)
		{
			setInter(Ni-1);
		}
	}
	else if(id==tbStart.id||id==tbEnd.id||id==bInter.id)
	{
		if(code==FLAT_ACTION_DEFAULT)
		{
			setInterval(	format.toDouble(tbStart.text),
							format.toDouble(tbEnd.text));
			buildData();
			setInter(Ni);
		}
	}
	else if(id==tbSamples.id||id==tbPoints.id||id==bSamples.id)
	{
		if(code==FLAT_ACTION_DEFAULT)
		{
			setSamples(	format.toInt(tbSamples.text),
						format.toInt(tbPoints.text));
			buildData();
			setInter(Ni);
		}
	}
	else if(id==bCapture.id)
	{
		Image image;
		InitInfo info;
		info.format.exposant=TRUE;
		info.format.precision=3;
		info.add(_T("Formula"),formula);
		info.addInt(_T("Samples"),N);
		info.add(_T("inter"),tbInter.text);
		screenshot(&image,fg.getRect());
		info.write(_T("capture.txt"));
		writeJPEG(_T("capture.jpg"),&image,85);
		File file;
		file.open(_T("capture.plt"),_T("wb"));
		fg.graph.save(file,TRUE,formula);
	}
	else if(id==bLog.id)
	{
		fg.graph.logscaleX=bLog.checked;
	}
	else
	{
		return FALSE;
	}
	return TRUE;
}
BOOL Inter::setSamples(int samples, int points)
{
	if(	samples<2||points<1||
		!vx.setSize(samples)||!vy.setSize(samples))
		return FALSE;
	N=samples;
	dN=points;
	tbSamples.setText(format.toString(N));
	tbPoints.setText(format.toString(dN));

	fg.graph.getChannelByName(_T("arg"))->setSource(&arg,N*dN);
	fg.graph.getChannelByName(_T("real"))->setSource(&rv,N*dN);
	fg.graph.getChannelByName(_T("inter"))->setSource(&iv,N*dN);
	fg.graph.getChannelByName(_T("error"))->setSource(&error,N*dN);
	fg.graph.getChannelByName(_T("real(inter)"))->setSource(&rv,N*dN);
	fg.graph.getChannelByName(_T("x_anchors"))->setSource(vx.elems,-vy.length);
	fg.graph.getChannelByName(_T("y_anchors"))->setSource(vy.elems,-vy.length);

	return TRUE;
}
void Inter::buildData()
{
	incData<double>(start,end,vx.length,vx.elems);
	incData<double>(start,end,vy.length,vy.elems,func);
}
void Inter::setInterval(double start, double end)
{
	this->start=start;
	this->end=end;
	tbStart.setText(format.toString(start));
	tbEnd.setText(format.toString(end));
}
BOOL Inter::setInter(int n)
{
	if(n<2)
		return FALSE;
	Ni=n;
	tbInter.setText(format.toString(Ni));
	interpolate();
	return TRUE;
}
BOOL Inter::create ()	
{
	Channel *tmp;

	FlatApplication::create();
	name=_T("Interpolator");

	display.width=800;
	display.height=600;

	format.precision=3;

	fontSmall.setFace(_T("Courier New"));
	fontSmall.height=-12;
	add(&fontSmall);

	fg.bgColor=INT_GRAY;
	fg.graph.clear();
	//fg.graph.smooth=TRUE;
	fg.graph.grid.set(3,5);
	fg.graph.margin=10;
	fg.graph.marginChannel.set(15,50);
	fg.graph.font=&fontSmall;
	fg.graph.formatX.precision=3;
	fg.graph.formatY.precision=3;
	fg.location.set(10,GRAPH_POS_Y);
	fg.margin.set(10,10);
	fg.font=&font;
	fg.fontColor=INT_BLACK;
	fg.graph.addChannel( _T("arg"));
	tmp=fg.graph.addChannel( _T("real"),_T("arg"),INT_BLUE);
	//tmp->symbol=_T("real");
	tmp=fg.graph.addChannel( _T("inter"),_T("arg"),INT_DGREEN);
	//tmp->symbol=_T("inter");
	tmp=fg.graph.addChannel( _T("error"),_T("arg"),INT_RED);
	//tmp->symbol=_T("error");
	tmp->hidden=TRUE;
	fg.graph.addChannel( _T("x_anchors"));
	fg.graph.addChannel( _T("y_anchors"),_T("x_anchors"),INT_BLACK,0,NULL,-10);
	fg.graph.addChannel( _T("real(inter)"),_T("inter"),INT_RED,0,NULL,2,TRUE,TRUE);

	tbInter.borderLine=1;
	tbInter.borderColor=INT_WGRAY;
	tbInter.activeLine=2;
	tbInter.font=&font;
	tbInter.fontColor=INT_BLACK;
	tbInter.margin.set(2,1);
	tbInter.setBounds(10,10,40,20);

	bPlus.text=_T("+");
	bPlus.borderLine=1;
	bPlus.borderColor=INT_GRAY;
	bPlus.overColor=INT_WHITE;
	bPlus.pressColor=INT_ORANGE;
	bPlus.activeLine=2;
	bPlus.font=&font;
	bPlus.fontColor=INT_BLACK;
	bPlus.margin.set(10,1);
	bPlus.bgColor=INT_YELLOW;
	bPlus.stick(DIR_RIGHT,5);

	bMin.copy(bPlus);
	bMin.text=_T("-");
	bMin.stick(DIR_RIGHT,3);

	tbStart.copy(tbInter);
	tbStart.size.x=70;
	tbStart.stick(DIR_RIGHT,5);

	tbEnd.copy(tbStart);
	tbEnd.stick(DIR_RIGHT,5);

	bInter.copy(bPlus);
	bInter.text=_T("Set");
	bInter.stick(DIR_RIGHT,5);

	tbSamples.copy(tbStart);
	tbSamples.size.x=40;
	tbSamples.stick(DIR_RIGHT,5);

	tbPoints.copy(tbSamples);
	tbPoints.stick(DIR_RIGHT,5);

	bSamples.copy(bPlus);
	bSamples.text=_T("Samples");
	bSamples.stick(DIR_RIGHT,5);

	bCapture.copy(bSamples);
	bCapture.text=_T("Capture");
	bCapture.stick(DIR_RIGHT,5);

	bLog.copy(bSamples);
	bLog.text=_T("Log");
	bLog.checkable=TRUE;
	bLog.stick(DIR_RIGHT,5);
	
	setSamples(DEF_SAMPLES,DEF_POINTS);
	setInterval(DEF_START,DEF_END);
	buildData();
	setInter(DEF_INTER);

	add(&fg);
	add(&tbInter);
	add(&bPlus);
	add(&bMin);
	add(&tbStart);
	add(&tbEnd);
	add(&bInter);
	add(&tbSamples);
	add(&tbPoints);
	add(&bSamples);
	add(&bCapture);
	add(&bLog);

	return TRUE;
}
void Inter::draw2D()
{
	
	font.x=10;
	font.y=50;
	font.color=INT_WHITE;
	glPrint(&font,_T("y=f(x)=%s"),formula);
	font.y+=18;
	font.color=INT_WGRAY;
	glPrint(&font,_T("Inter: %2d, Mean: %+.3le, Dev:  %.3le"),Ni,stat.mean(),stat.stdev());
}

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	return inter.main(hInstance,hPrevInstance,lpCmdLine,nCmdShow);
}
